﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using mtTools;
using NHibernate;

namespace mtWebDraw.DAL
{

    /// <summary>
    /// NHibernate数据库操作类（用于非IOC模式）：即时处理请求无缓存
    /// </summary>
    public static class NHibernateDal
    {

        #region SessionFactory构造

        /// <summary>
        /// NHibernate的xml配置文件地址
        /// </summary>
        private static string ConfigPath = null;

        /// <summary>
        /// ISessionFactory全局唯一实例对象
        /// </summary>
        public static ISessionFactory SessionFactory = null;

        /// <summary>
        /// 构造方法：初始化ConfigPath和SessionFactory
        /// </summary>
        static NHibernateDal()
        {
            ConfigPath = System.AppDomain.CurrentDomain.BaseDirectory + ConfigHelper.GetAppSettingValue("nhConfigPath");
            SessionFactory = new NHibernate.Cfg.Configuration().Configure(ConfigPath).BuildSessionFactory();
        }

        #endregion

        #region Insert、Update、Delete

        /// <summary>
        /// 保存一条数据：成功返回ID，失败返回null
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static object Insert<T>(T obj) where T : class
        {
            ISession session = SessionFactory.OpenSession();
            ITransaction trans = session.BeginTransaction();
            try
            {
                Object temp = session.Save(obj);

                if (temp != null) //保存成功
                    trans.Commit();
                else
                    trans.Rollback();

                return temp;
            }
            catch (Exception ex)
            {
                trans.Rollback();
                ex.WriteFile("Insert", "【obj】" + obj.JSONSerialize());
                return null;
            }
            finally
            {
                session.Close();
            }
        }

        /// <summary>
        /// 批量插入多条数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static bool Insert<T>(List<T> list)
        {
            IStatelessSession session = SessionFactory.OpenStatelessSession();
            ITransaction trans = session.BeginTransaction();
            try
            {
                Object temp = null;
                foreach (T item in list)
                {
                    temp = session.Insert(item);

                    if (temp == null) //保存失败
                    {
                        trans.Rollback();
                        return false;
                    }
                }

                trans.Commit();
                return true;
            }
            catch (Exception ex)
            {
                trans.Rollback();
                ex.WriteFile("Insert", "【list】" + list.JSONSerialize());
                return false;
            }
            finally
            {
                session.Close();
            }
        }

        /// <summary>
        /// 更新一条数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool Update<T>(T obj) where T : class
        {
            ISession session = SessionFactory.OpenSession();
            ITransaction trans = session.BeginTransaction();
            try
            {
                session.Update(obj);
                trans.Commit();
                return true;
            }
            catch (Exception ex)
            {
                trans.Rollback();
                ex.WriteFile("Update", "【obj】" + obj.JSONSerialize());
                return false;
            }
            finally
            {
                session.Close();
            }
        }

        /// <summary>
        /// 批量更新多条数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static bool Update<T>(List<T> list)
        {
            IStatelessSession session = SessionFactory.OpenStatelessSession();
            ITransaction trans = session.BeginTransaction();
            try
            {
                foreach (T item in list)
                {
                    session.Update(item);
                }

                trans.Commit();
                return true;
            }
            catch (Exception ex)
            {
                trans.Rollback();
                ex.WriteFile("Update", "【list】" + list.JSONSerialize());
                return false;
            }
            finally
            {
                session.Close();
            }
        }

        /// <summary>
        /// 删除一条数据：先查询再删除的老方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool Delete<T>(object id)
        {
            ISession session = SessionFactory.OpenSession();
            ITransaction trans = session.BeginTransaction();
            try
            {
                T obj = session.Load<T>(id);
                session.Delete(obj);
                trans.Commit();
                return true;
            }
            catch (Exception ex)
            {
                trans.Rollback();
                ex.WriteFile("Delete", "【id】" + id);
                return false;
            }
            finally
            {
                session.Close();
            }
        }

        /// <summary>
        /// 删除多条数据：成功返回删除记录数，失败返回0：不符合ORM思想，尽量少用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query">例：from tUser Where ID = '999'</param>
        /// <returns></returns>
        public static int Delete<T>(string query)
        {
            ISession session = SessionFactory.OpenSession();
            ITransaction trans = session.BeginTransaction();
            try
            {
                int count = session.Delete(query);

                if (count != 0) //保存成功
                    trans.Commit();
                else
                    trans.Rollback();

                return count;
            }
            catch (Exception ex)
            {
                trans.Rollback();
                ex.WriteFile("Delete", "【query】" + query);
                return -1;
            }
            finally
            {
                session.Close();
            }
        }

        #endregion

        #region ICriteria

        /// <summary>
        /// 符加查询条件
        /// </summary>
        /// <param name="list">ICriteria查询对象</param>
        /// <param name="Where">查询条件：And方式，==操作</param>
        /// <param name="OrderBy">排序条件：从前向后依次作用</param>
        /// <param name="Like">模糊查询条件：And方式，支持开始、结束、部分、全部四种匹配方式</param>
        private static void CreateQuery(ref ICriteria list, Dictionary<string, object> Where, Dictionary<string, OrderByType> OrderBy, List<PropertyLike> Like)
        {

            #region 条件查询

            if (Where != null && Where.Count > 0)
            {
                foreach (var item in Where)
                {
                    list.Add(NHibernate.Criterion.Expression.Eq(item.Key, item.Value));
                }
            }

            #endregion

            #region 模糊查询

            if (Like != null && Like.Count > 0)
            {
                foreach (var item in Like)
                {
                    NHibernate.Criterion.MatchMode mode = NHibernate.Criterion.MatchMode.Anywhere; //默认为%str%
                    if (item.mode == MatchMode.Start)
                        mode = NHibernate.Criterion.MatchMode.Start;
                    else if (item.mode == MatchMode.End)
                        mode = NHibernate.Criterion.MatchMode.End;
                    else if (item.mode == MatchMode.Exact)
                        mode = NHibernate.Criterion.MatchMode.Exact;
                    else if (item.mode == MatchMode.Anywhere)
                        mode = NHibernate.Criterion.MatchMode.Anywhere;

                    list.Add(NHibernate.Criterion.Expression.Like(item.name, item.value, mode));
                }
            }

            #endregion

            #region 排序

            if (OrderBy != null && OrderBy.Count > 0)
            {
                foreach (var item in OrderBy)
                {
                    //true:asc;false:desc
                    if (item.Value == OrderByType.Asc)
                    {
                        list.AddOrder(NHibernate.Criterion.Order.Asc(item.Key));
                    }
                    else
                    {
                        list.AddOrder(NHibernate.Criterion.Order.Desc(item.Key));
                    }

                }
            }

            #endregion

        }

        #endregion

        #region Count

        /// <summary>
        /// 查询数据记录总数量
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns>所有符合条件的数据记录总数量</returns>
        public static int Count<T>()
        {
            return Count<T>(null, null);
        }

        /// <summary>
        /// 查询数据记录总数量
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Where">查询条件：And方式，==操作</param>
        /// <returns>所有符合条件的数据记录总数量</returns>
        public static int Count<T>(Dictionary<string, object> Where)
        {
            return Count<T>(Where, null);
        }

        /// <summary>
        /// 查询数据记录总数量
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Where">查询条件：And方式，==操作</param>
        /// <param name="Like">模糊查询条件：And方式，支持开始、结束、部分、全部四种匹配方式</param>
        /// <returns>所有符合条件的数据记录总数量</returns>
        public static int Count<T>(Dictionary<string, object> Where, List<PropertyLike> Like)
        {
            ISession session = SessionFactory.OpenSession();
            ICriteria list = session.CreateCriteria(typeof(T));

            CreateQuery(ref list, Where, null, Like);
            list.SetProjection(NHibernate.Criterion.Projections.RowCount());

            int TotalCount = list.UniqueResult<int>();

            session.Close();
            return TotalCount;
        }

        #endregion

        #region Select：不分页

        /// <summary>
        /// 查询指定记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id">记录主键标识</param>
        /// <returns>返回数据对象</returns>
        public static T Select<T>(object id)
        {
            ISession session = SessionFactory.OpenSession();
            T obj = session.Get<T>(id);
            session.Close();
            return obj;
        }

        /// <summary>
        /// 查询所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns>所有符合条件的数据记录</returns>
        public static IList<T> Select<T>()
        {
            return Select<T>(null, null, null);
        }

        /// <summary>
        /// 查询所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="OrderBy">排序条件：从前向后依次作用</param>
        /// <returns>所有符合条件的数据记录</returns>
        public static IList<T> Select<T>(Dictionary<string, OrderByType> OrderBy)
        {
            return Select<T>(null, OrderBy, null);
        }

        /// <summary>
        /// 查询所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Where">查询条件：And方式，==操作</param>
        /// <returns>所有符合条件的数据记录</returns>
        public static IList<T> Select<T>(Dictionary<string, object> Where)
        {
            return Select<T>(Where, null, null);
        }

        /// <summary>
        /// 查询所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Where">查询条件：And方式，==操作</param>
        /// <param name="OrderBy">排序条件：从前向后依次作用</param>
        /// <returns>所有符合条件的数据记录</returns>
        public static IList<T> Select<T>(Dictionary<string, object> Where, Dictionary<string, OrderByType> OrderBy)
        {
            return Select<T>(Where, OrderBy, null);
        }

        /// <summary>
        /// 查询所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Where">查询条件：And方式，==操作</param>
        /// <param name="OrderBy">排序条件：从前向后依次作用</param>
        /// <param name="Like">模糊查询条件：And方式，支持开始、结束、部分、全部四种匹配方式</param>
        /// <returns>所有符合条件的数据记录</returns>
        public static IList<T> Select<T>(Dictionary<string, object> Where, Dictionary<string, OrderByType> OrderBy, List<PropertyLike> Like)
        {
            ISession session = SessionFactory.OpenSession();
            ICriteria list = session.CreateCriteria(typeof(T));

            CreateQuery(ref list, Where, OrderBy, Like);
            IList<T> result = list.List<T>();

            session.Close();
            return result;
        }

        #endregion

        #region Select：分页

        /// <summary>
        /// 查询分页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="PageIndex">当前页码：从1开始</param>
        /// <param name="PageSize">每页记录数</param>
        /// <param name="TotalCount">返回符合条件的总记录数</param>
        /// <returns>当前页符合条件的数据记录</returns>
        public static IList<T> Select<T>(int PageIndex, int PageSize, out int TotalCount)
        {
            return Select<T>(null, null, null, PageIndex, PageSize, out TotalCount);
        }

        /// <summary>
        /// 查询分页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="OrderBy">排序条件：从前向后依次作用</param>
        /// <param name="PageIndex">当前页码：从1开始</param>
        /// <param name="PageSize">每页记录数</param>
        /// <param name="TotalCount">返回符合条件的总记录数</param>
        /// <returns>当前页符合条件的数据记录</returns>
        public static IList<T> Select<T>(Dictionary<string, OrderByType> OrderBy, int PageIndex, int PageSize, out int TotalCount)
        {
            return Select<T>(null, OrderBy, null, PageIndex, PageSize, out TotalCount);
        }

        /// <summary>
        /// 查询分页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Where">查询条件：And方式，==操作</param>
        /// <param name="OrderBy">排序条件：从前向后依次作用</param>
        /// <param name="PageIndex">当前页码：从1开始</param>
        /// <param name="PageSize">每页记录数</param>
        /// <param name="TotalCount">返回符合条件的总记录数</param>
        /// <returns>当前页符合条件的数据记录</returns>
        public static IList<T> Select<T>(Dictionary<string, object> Where, Dictionary<string, OrderByType> OrderBy, int PageIndex, int PageSize, out int TotalCount)
        {
            return Select<T>(Where, OrderBy, null, PageIndex, PageSize, out TotalCount);
        }

        /// <summary>
        /// 查询分页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Where">查询条件：And方式，==操作</param>
        /// <param name="OrderBy">排序条件：从前向后依次作用</param>
        /// <param name="Like">模糊查询条件：And方式，支持开始、结束、部分、全部四种匹配方式</param>
        /// <param name="PageIndex">当前页码：从1开始</param>
        /// <param name="PageSize">每页记录数</param>
        /// <param name="TotalCount">返回符合条件的总记录数</param>
        /// <returns>当前页符合条件的数据记录</returns>
        public static IList<T> Select<T>(Dictionary<string, object> Where, Dictionary<string, OrderByType> OrderBy, List<PropertyLike> Like, int PageIndex, int PageSize, out int TotalCount)
        {
            TotalCount = Count<T>(Where, Like);

            ISession session = SessionFactory.OpenSession();
            ICriteria list = session.CreateCriteria(typeof(T));

            CreateQuery(ref list, Where, OrderBy, Like);

            list.SetFirstResult((PageIndex - 1) * PageSize).SetMaxResults(PageSize);
            IList<T> result = list.List<T>();

            session.Close();
            return result;
        }

        #endregion

        #region Select：执行Sql语句以查询

        /// <summary>
        /// 查询数据：执行Sql语句
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Sql"></param>
        /// <returns></returns>
        public static IList<T> Select<T>(string Sql)
        {
            ISession session = SessionFactory.OpenSession();
            var list = session.CreateSQLQuery(Sql).AddEntity(typeof(T));

            IList<T> result = list.List<T>();

            session.Close();
            return result;
        }

        #endregion

    }

    /// <summary>
    /// Nhibernate的排序方式
    /// </summary>
    public enum OrderByType
    {
        /// <summary>
        /// 正序
        /// </summary>
        Asc = 0,
        /// <summary>
        /// 倒序
        /// </summary>
        Desc = 1
    }

    /// <summary>
    /// Nhibernate的Like查询类
    /// </summary>
    public class PropertyLike
    {

        /// <summary>
        /// Nhibernate的Like查询类
        /// </summary>
        /// <param name="name">PropertyName</param>
        /// <param name="value">PropertyLikeValue</param>
        /// <param name="mode">Like方式</param>
        public PropertyLike(string propertyName, string propertyLikeValue, MatchMode matchMode)
        {
            this.name = propertyName;
            this.value = propertyLikeValue;
            this.mode = matchMode;
        }

        /// <summary>
        /// PropertyName
        /// </summary>
        public string name { get; set; }

        /// <summary>
        /// PropertyLikeValue
        /// </summary>
        public string value { get; set; }

        /// <summary>
        /// Like方式
        /// </summary>
        public MatchMode mode { get; set; }

    }

    /// <summary>
    /// Like方式
    /// </summary>
    public enum MatchMode
    {
        /// <summary>
        /// 完全匹配，相当于==
        /// </summary>
        Exact,

        /// <summary>
        /// 出现在起始位置，相当于 %str
        /// </summary>
        Start,

        /// <summary>
        /// 出现在最后位置，相当于 str%
        /// </summary>
        End,

        /// <summary>
        /// 表示任何位置匹配，相当于 %str%
        /// </summary>
        Anywhere
    }

    /// <summary>
    /// NHibernate辅助类
    /// </summary>
    public static class NH
    {

        /// <summary>
        /// 创建Where空集合
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, object> CreateWhere()
        {
            
            return new Dictionary<string, object>();
        }

        /// <summary>
        /// 创建Where集合
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, object> CreateWhere(string k, object v)
        {
            var kv = new Dictionary<string, object>();
            kv.Add(k, v);
            return kv;
        }

        /// <summary>
        /// 创建OrderBy空集合
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, OrderByType> CreateOrderBy()
        {
            return new Dictionary<string, OrderByType>();
        }

        /// <summary>
        /// 创建OrderBy空集合
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, OrderByType> CreateOrderBy(string k, OrderByType by)
        {
            var list = new Dictionary<string, OrderByType>();
            list.Add(k, by);
            return list;
        }

        /// <summary>
        /// 创建Like空集合
        /// </summary>
        /// <returns></returns>
        public static List<PropertyLike> CreateLike()
        {
            return new List<PropertyLike>();
        }

        /// <summary>
        /// 创建Like集合
        /// </summary>
        /// <returns></returns>
        public static List<PropertyLike> CreateLike(PropertyLike item)
        {
            var like = new List<PropertyLike>();
            like.Add(item);
            return like;
        }

    }

}
